package main

import (
	"fmt"
	"reflect"
)

// 定义学生结构体
type Student struct {
	Name string
	Age  int
}

// 给结构体绑定方法（方法顺序按照首字母）
func (s Student) AGetSum(n1, n2 int) int {
	return n1 + n2
}

// 给结构体绑定方法
func (s Student) BSet(name string, age int) {
	s.Name = name
	s.Age = age
}

// 给结构体绑定方法
func (s Student) CPrint() {
	fmt.Println("----start----")
	fmt.Println("Name:", s.Name)
	fmt.Println("Age:", s.Age)
	fmt.Println("----end----")
}

// 定义函数操作结构体进行反射操作
func testReflect(b interface{}) {
	//通过反射获取传入的变量的 type, kind, 值
	//1. 先获取到 reflect.Type
	rTyp := reflect.TypeOf(b)
	fmt.Println("rType=", rTyp)

	//2. 获取到 reflect.Value
	rVal := reflect.ValueOf(b)
	fmt.Println("rVal=", rVal)

	// 获取变量的类别
	kind1 := rTyp.Kind()
	fmt.Println("kind1=", kind1)

	kind2 := rVal.Kind()
	fmt.Println("kind2=", kind2)

	// 获取字段个数
	num := rVal.NumField()
	fmt.Printf("struct has %d fields\n", num)

	// 变量结构体的所有字段
	for i := 0; i < num; i++ {
		fmt.Printf("Field %d: 值=%v\n", i, rVal.Field(i))
		// 获取字段的 tag
		tagVal := rTyp.Field(i).Tag.Get("json")
		// 如果该字段有 tag 标签，就显示，否则就不显示
		if tagVal != "" {
			fmt.Printf("Field %d: tag=%v\n", i, tagVal)
		}
	}

	// 获取该结构体有多少个方法
	numOfMethod := rVal.NumMethod()
	fmt.Printf("struct has %d methods\n", numOfMethod)

	// 调用结构体的第一个方法
	var params []reflect.Value
	params = append(params, reflect.ValueOf(10))
	params = append(params, reflect.ValueOf(40))
	res := rVal.Method(0).Call(params)
	fmt.Println("res=", res[0].Int())

	// 调用结构体的第二个方法BSet
	// 注意传入的参数是 []reflect.Value
	rVal.Method(1).Call([]reflect.Value{reflect.ValueOf("mary"), reflect.ValueOf(28)})

	// 调用结构体的第三个方法
	rVal.Method(2).Call(nil)
}

func main() {
	//第十四章 反射

	// 定义一个student实例
	stu := Student{
		Name: "tom",
		Age:  20,
	}

	// 调用 testReflect 函数，传入 num
	testReflect(stu)
}
